第一階段的最後一天,來看看這個方便的工具--Docker Compose。Docker Compose 是用來組合多個 container 成為一個完整服務的工具。先前在說明如何連結 container 時,已經有示範過連結 container 的基本方法。雖然可行,但要執行非常多指令才能把 container 串起來。Docker Compose 不只可以做到一樣的事,而且它使用 YAML 描述檔定義 container 的關係,簡化定義的過程,同時也實現了 IaC,讓 container 的關係可以簽入版本控制。
Docker Compose 最終結果是啟動 container,底層一樣會使用 docker run
指令,因此 Docker Compose 的設定參數會與 docker run
的選項和參數非常相似,這也是筆者選擇先詳細說明指令後,才開始介紹 Docker Compose 的原因。
以下會拿過去幾天曾看過的範例,改寫成 Docker Compose 格式。讀者可以看看 Docker 與 Docker Compose 之間如何轉換。
首先小試身手,以 Container 應用 裡提到的 node.js + npm 為例。
docker run -it --rm -v \$PWD:/source -w /source node:14-alpine
Docker Compose 使用 docker-compose.yml
做為預設載入設定的檔名,首先建立這個檔案,並輸入以下內容:
# 使用 3.8 版的設定檔,通常新版本會有新的功能,並支援新的設定參數
version: "3.8"
# 定義 service 的區塊,一個 service 設定可以用來啟動多個 container
services:
# 定義一個叫 npm 的 service
npm:
image: node:14-alpine
stdin_open: true
tty: true
working_dir: /source
volumes:
- .:/source
主要架構的說明可參考上面的註解,從 container 定義裡可以發現,跟 docker run
指令的選項或參數非常像。
image
是指 IMAGE 參數stdin_open
是 --interactive
選項;tty
是 --tty
選項,這在了解 docker run 指令有提過working_dir
是 Container 應用 有提到的 --workdir
選項volumes
是使用 volume 同步程式有提過的 --volume
選項定義好後,使用 docker-compose run
指令,即可達成與 docker run
一樣的效果:
docker-compose run --rm npm npm -v
一樣是 Container 應用裡有提到的多環境執行單元測試:
docker run -it --rm -v $PWD:/source -w /source php:7.1-alpine vendor/bin/phpunit
docker run -it --rm -v $PWD:/source -w /source php:7.2-alpine vendor/bin/phpunit
docker run -it --rm -v $PWD:/source -w /source php:7.3-alpine vendor/bin/phpunit
docker run -it --rm -v $PWD:/source -w /source php:7.4-alpine vendor/bin/phpunit
改使用 docker-compose.yml
的定義如下:
version: "3.8"
services:
php71: &basic
image: php:7.1-alpine
stdin_open: true
tty: true
working_dir: /source
volumes:
- .:/source
command: vendor/bin/phpunit
php72:
<<: *basic
image: php:7.2-alpine
php73:
<<: *basic
image: php:7.3-alpine
php74:
<<: *basic
image: php:7.4-alpine
php80:
<<: *basic
image: php:8.0.0beta4-alpine
這個設定檔用了 YAML 的語法,讓文件內容可以被參考與重用。
command
定義了啟動 container 會執行的指令,以 docker run
的例子,這裡要填的是 vendor/bin/phpunit
。照上面單一 container 的範例,可以猜得出來指令應該要這樣下:
docker-compose run --rm php71
docker-compose run --rm php72
docker-compose run --rm php73
docker-compose run --rm php74
docker-compose run --rm php80
但一個一個執行還是有點麻煩,這裡改用另一個指令:
docker-compose up
這個指令可以看到它同時間併發執行五個 container,並能在最後看到全部的結果。
跟執行單個 container 狀況不同,因為多個 container 的狀況下,無法同時綁定終端機的輸入在每個 container 上,所以通常這個情境都是觀察 log 或是背景執行。
以使用 environment 控制環境變數裡提到的 phpMyAdmin + MySQL 為例。
# Terminal 1
docker run --rm -it --name db -e MYSQL_ROOT_PASSWORD=pass -e MYSQL_DATABASE=some percona
# Terminal 2
docker run --rm -it --link db -p 8080:80 phpmyadmin
轉換成 docker-compose.yml
檔如下:
version: "3.8"
services:
database:
image: percona
environment:
MYSQL_ROOT_PASSWORD: pass
MYSQL_DATABASE: some
phpmyadmin:
image: phpmyadmin
ports:
- 8080:80
links:
- database:db
environment
即 --env
ports
為 -p
即開出去的 port 設定links
為連接 container所提到的 --link
執行指令:
# 直接前景執行,當中斷的時候,會停止所有 container。GIF 範例使用下面的指令
# docker-compose up
# 背景執行
docker-compose up -d
# 查看 log
docker-compose logs -f
延續連結多個 container,我們再加一個 Wordpress 服務,這次來直接修改 docker-compose.yml
檔:
version: "3.8"
services:
database:
image: percona
environment:
MYSQL_ROOT_PASSWORD: pass
MYSQL_DATABASE: some
phpmyadmin:
image: phpmyadmin
ports:
- 8080:80
links:
- database:db
wordpress:
image: wordpress
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: root
WORDPRESS_DB_PASSWORD: pass
WORDPRESS_DB_NAME: some
ports:
- 80:80
links:
- database:db
接著再次執行指令:
# 背景執行
docker-compose up -d
# 查看 wordpress 的 log
docker-compose logs wordpress
docker-compose.yml
檔有修改,所以它會針對修改的部分做更新,以本例來說是要啟動 wordpress。
docker-compose run
用法:
docker-compose run [options] SERVICE [COMMAND]
與 docker run
非常像,但大部分的選項或參數都是取自於 YAML 裡的設定。
COMMAND
為啟動 service 後,要執行的指令--rm
與 docker run
的 --rm
用法一樣,當 container 結束的時候就移除 containerdocker-compose up
用法:
docker-compose up [options] [SERVICE...]
建立並啟動所有 YAML 定義裡所有的 container。
SERVICE
為 YAML 定義的 service 名稱,當沒有帶參數時,會建立並啟動所有 service,有帶則僅建立啟動該 service-d
與 docker run
的 -d
用法一樣,讓 container 在背景執行docker-compose logs
用法:
docker-compose logs [options] [SERVICE...]
查看 container 的標準輸出內容,以到目前為止的範例,都是 log 居多。
SERVICE
為 YAML 定義的 service 名稱,當沒有帶參數時,會顯示所有 service log,有帶則會僅顯示該 service 的 log-f
當 container log 有更新時,會自動更新到畫面上到目前為止,docker run
以及 Docker Compose 已經能幫助開發者輕鬆建立與部署開發用的測試環境,而且砍掉重練都非常容易,就算壞掉也不需要太擔心。